import { defineStore } from 'pinia'

interface Job {
  name: string,
  vm?: Vm,
  sched: boolean,
  // program: Function
  data: Array<number>
  log: string[],
  schenum: number,
  failsche: string,
  state: string
}

interface Vm {
  name: string,
  server: Server,
  isActive: boolean
  jobs: Job[]
}

interface Server {
  name: string
  icon: string
  isActive: boolean
  vms: Vm[]
}

function getTime(){
  var date=new Date();
  var year=date.getFullYear();
  var month=date.getMonth()+1;
  month=month<10?"0"+month:month;
  var day=date.getDate();
  day=day<10?"0"+day:day;
  var week="日一二三四五六".charAt(date.getDay());
  var hour=date.getHours();
  hour=hour<10?"0"+hour:hour;
  var minute=date.getMinutes();
  minute=minute<10?"0"+minute:minute;
  var second=date.getSeconds();
  second=second<10?"0"+second:second;
  
  var current=year+"-"+month+"-"+day+" "+hour+":"+minute+":"+second;
  return current
}

function log(str) {
  return '[' + getTime() + ']: ' + str
}

function randomIntFromInterval(min, max) { // min and max included 
  return Math.floor(Math.random() * (max - min + 1) + min)
}

export const useDataStore = defineStore('servers', {
  state: () => ({ servers: [] as Server[], vms: [] as Vm[], jobs: [] as Job[] }),
  getters: {},
  actions: {
    addServer(name: string) {
      let server: Server = {
        name: name,
        icon: 'ant-design:cloud-server-outlined',
        isActive: true,
        vms: [],
      }
      this.servers.push(server)

      for (let i = 1; i <= 5; i++) {
        let vm: Vm = {
          name: 'vm-' + i,
          server: server,
          isActive: true,
          jobs: [],
        }
        this.vms.push(vm)
        server.vms.push(vm)
      }
    },
    addJob(name: string, failsche: string) {
      let vm = this.selectVm()
      let job: Job = {
        name: name,
        sched: false,
        data: [],
        log: [log('Schedule to: ' + vm.server.name + ' ' + vm.name)],
        schenum: 1,
        failsche: failsche,
        vm: vm,
        state: 'run'
      }
      vm.jobs.push(job)
      
      let program = setInterval(() => {
        if (job.state != 'run') {
          return
        }
        let r = 1
        if (job.data.length > 1) {
          r = job.data[job.data.length - 1] + job.data[job.data.length - 2]
        }
        job.data.push(r)
        job.log.push(log(r))
      }, 2000)
      this.jobs.push(job)
    },
    addJobs(num: number, failsche: string) {
      for (let i = 1; i <= num; i++) {
        this.addJob('Fibonacci-' + i, failsche)
      }
    },
    selectVm() {
      let r = this.vms.filter(v => v.isActive && v.server.isActive)[0]
      for (let vm of this.vms) {
        if (vm.isActive && vm.server.isActive && vm.jobs.length < r.jobs.length) {
          r = vm
        }
      }
      console.log(r.server.isActive)
      return r
    },
    selectVmRegex(regex: string) {
      let reg = new RegExp(regex)
      let r = this.vms.filter(v => v.isActive).filter(vm => {
        let name = vm.server.name + '-' + vm.name;
        return reg.test(name);
      })
      if (r.length == 0) {
        return false
      }
      let out = r[0];
      for (let vm of r) {
        if (vm.isActive && vm.jobs.length < out.jobs.length) {
          out = vm
        }
      }
      return out
    },
    scheduleJob(job: Job, isFail=false) {
      let r: boolean | Vm | undefined;
      if (isFail && job.failsche == 'samevm') {
        console.log(job.vm.name + '.*')
        r = this.selectVmRegex(job.vm?.server.name + '.*')
        if (r == false) {
          r = this.selectVm()
        }
      } else {
        r = this.selectVm()
      }
      console.log(r)
      if (job.vm == r) {
        return
      }
      job.state = 'sche'
      job.vm.jobs = job.vm.jobs.filter(j => j != job)
      job.vm = r
      job.vm.jobs.push(job)
      setTimeout(() => {
        job.state = 'run'
        job.schenum++
        job.log.push(log('Schedule to: ' + r.server.name + ' ' + r.name))
      }, randomIntFromInterval(15, 25) * 1000)
    },
    setServerState(server, state) {
      if (server.isActive == state) {
        return
      }
      server.isActive = state
      if (state == false) {
        console.log(server)
        server.vms.forEach(vm => this.setVmState(vm, false))
      }
    },
    setVmState(vm, state) {
      if (vm.isActive == state) {
        return 0
      }
      if (!vm.server.isActive && state == true) {
        return 2
      }
      vm.isActive = state
      if (state == false) {
        vm.jobs.forEach(job => {
          this.scheduleJob(job, true)
        });
      } else {
        this.servers.forEach(server => {
          server.vms.forEach(vm => {
            vm.jobs.forEach(job => this.scheduleJob(job, false))
          })
        })
      }
      return 0;
    }
  },
})
